﻿// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision$</version>
// </file>

using System;
using System.Collections.Generic;

namespace ICSharpCode.TextEditor.Document
{
    /// <summary>
    /// A simple folding strategy which calculates the folding level
    /// using the indent level of the line.
    /// </summary>
    public class CSharpFoldingStrategy : IFoldingStrategy
    {
        int GetLevel(IDocument document, int offset)
        {
            int level = 0;
            int spaces = 0;
            for (int i = offset; i < document.TextLength; ++i)
            {
                char c = document.GetCharAt(i);
                if (c == '\t' || (c == ' ' && ++spaces == 4))
                {
                    spaces = 0;
                    ++level;
                }
                else
                {
                    break;
                }
            }
            return level;
        }

        FoldMarker FindLast(List<FoldMarker> list)
        {
            return list[list.Count - 1];
        }

        public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
        {
            return GenerateFoldMarkers(document);
        }

        public List<FoldMarker> GenerateFoldMarkers(IDocument document)
        {
            List<FoldMarker> list = new List<FoldMarker>();

            Stack<int> startLines = new Stack<int>();
            Stack<string> startTextLines = new Stack<string>();

            int import_end_line = 0;
            var import_end = false;
            var import_start = false;           
            var import_start_label = "";

            var summary_start_line = 0;
            var summary_start = false;
            var summary_start_label = "";

            // Create foldmarkers for the whole document, enumerate through every line.
            for (int i = 0; i < document.TotalNumberOfLines; i++)
            {
                var seg = document.GetLineSegment(i);
                int offs, end = document.TextLength;
                char c;
                for (offs = seg.Offset; offs < end && ((c = document.GetCharAt(offs)) == ' ' || c == '\t'); offs++)
                {
                    //offs 增加
                }
                if (offs == end)
                    break;

                int spaceCount = offs - seg.Offset;

                // now offs points to the first non-whitespace char on the line

                int start = 0;
                char dott = document.GetCharAt(offs);
                string text = document.GetText(offs, seg.Length - spaceCount);

                //import               
                if (!import_end && text.Trim().StartsWith("using", StringComparison.OrdinalIgnoreCase))
                {
                    if (!import_start)
                    {
                        startLines.Push(i);
                        import_start = true;
                        import_start_label = text;
                    }
                    import_end_line = i;
                    startTextLines.Push(text);
                }
                if (import_start && !import_end && !string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text.Trim()))
                {
                    if (!text.Trim().StartsWith("using", StringComparison.OrdinalIgnoreCase))
                    {
                        start = startLines.Pop();
                        string regionLabel = startTextLines.Pop();
                        string regionText = "using ...";
                        list.Add(new FoldMarker(document, start, document.GetLineSegment(start).Length - import_start_label.Length, import_end_line, spaceCount + import_start_label.Length + regionLabel.Length + regionText.Length, FoldType.Unspecified, regionText));

                        import_start = false;
                        import_end = true;
                    }
                }              

                if (!string.IsNullOrEmpty(text))
                {
                    switch (dott)
                    {
                        case '#':

                            if (text.StartsWith("#region"))
                            {
                                startLines.Push(i);
                                startTextLines.Push(text);                                
                            }
                            if (text.StartsWith("#endregion") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop();

                                string regionLabel = startTextLines.Pop();
                                string regionText = regionLabel.Replace("#region", "").Trim();

                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length - regionLabel.Length,
                                    i, spaceCount + "#region".Length + "endregion".Length + regionLabel.Length,
                                    FoldType.Region, regionText)); 
                              
                             }

                            break;

                        case '/':

                            if (text.StartsWith("/// <summary>") || text.StartsWith("///<summary>"))
                            {
                                startLines.Push(i);
                                summary_start_label = "";
                                summary_start_line = i;
                                summary_start = true;
                                continue;
                            }
                            if (summary_start && text.StartsWith("///") && text.IndexOf("</summary>") == -1)
                            {
                                string spaceString = "";
                                if (!string.IsNullOrEmpty(summary_start_label))
                                    spaceString = " ";
                                summary_start_label += spaceString + text.Replace("///", "").Trim();
                                //summary_start = false;
                            }
                            if ((text.StartsWith("/// </summary>") || text.StartsWith("///</summary>")) && startLines.Count > 0)
                            {
                                summary_start = false;                                
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop();
                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length - "/// <summary>".Length,
                                    i, spaceCount + "/// </summary>".Length, FoldType.TypeBody, summary_start_label));
                            }
                            if (text.StartsWith("/// <param name="))
                            {
                                list[list.Count - 1] = new FoldMarker(document, summary_start_line,
                                    document.GetLineSegment(summary_start_line).Length - "/// <summary>".Length,
                                    i, spaceCount + 100,FoldType.TypeBody, summary_start_label);
                            }
                            if (text.StartsWith("/// <remarks>"))
                            {
                                list[list.Count - 1] = new FoldMarker(document, summary_start_line,
                                    document.GetLineSegment(summary_start_line).Length - "/// <summary>".Length,
                                    i, spaceCount + 100, FoldType.TypeBody, summary_start_label);

                                summary_start_label = "";
                            }
                            if (text.StartsWith("/// <returns>"))
                            {
                                //int startSubStringIndex = text.IndexOf("<returns>");
                                //int endSubStringIndex = text.IndexOf("</returns>");
                                //string markString = " " + text.Replace("///", "return: ")
                                //    .Replace("</returns>", "").Replace("<returns>", "").Trim();

                                //string markString = text.Replace("///", "").Trim();
                                //if (!string.IsNullOrEmpty(summary_start_label))
                                //    markString = " " + markString;

                                string markString = "";
                                if (string.IsNullOrEmpty(summary_start_label))
                                    markString = text.Replace("///", "").Trim();

                                //if (startSubStringIndex != -1 && endSubStringIndex != -1)
                                //    markString = " " + text.Substring(startSubStringIndex + "<returns>".Length, endSubStringIndex - startSubStringIndex);

                                list[list.Count - 1] = new FoldMarker(document, summary_start_line,
                                    document.GetLineSegment(summary_start_line).Length - "/// <summary>".Length,
                                    i, spaceCount + 100, FoldType.TypeBody, summary_start_label + markString);

                                summary_start_label = "";
                            }

                            break;

                        case '{':
                        case '}':

                            //text = document.GetText(offs, seg.Length - spaceCount);
                            if (text.StartsWith("{"))
                                startLines.Push(i);
                            if (text.StartsWith("}") && startLines.Count > 0)
                            {
                                // Add a new FoldMarker to the list.
                                start = startLines.Pop() - 1;                                
                                list.Add(new FoldMarker(document, start,
                                    document.GetLineSegment(start).Length,
                                    i, spaceCount + 100, FoldType.TypeBody));
                            }

                            break;

                    }

                }


            }

            return list;
        }

    }
}
